package cn.usbtg.poi.ext.download;

import cn.usbtg.poi.ext.download.bean.POITitle;
import cn.usbtg.poi.ext.download.celltheme.POICellThemeDefault;
import cn.usbtg.poi.ext.download.dataloader.POIDataLoader;
import cn.usbtg.poi.ext.download.dataloader.POIDataLoaderJson;
import cn.usbtg.poi.ext.download.dataloader.POIDataLoaderMap;
import cn.usbtg.poi.ext.download.style.POIStyleUtil;
import cn.usbtg.poi.ext.download.typeenum.POIFileSaveType;
import cn.usbtg.poi.ext.download.typeenum.POIFileType;
import cn.usbtg.sutil.EmptyUtil;
import cn.usbtg.sutil.Identities;
import com.alibaba.fastjson.JSONObject;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 默认主题下载
 */
public class POIDownload {

    /**
     * 生成excel
     *
     * @param filePath      文件保存路径
     * @param fileName      文件名
     * @param fileType      文件类型
     * @param titles        标题配置
     * @param datas         数据集
     * @param POIDataLoader 数据加载器
     * @param autoWidth     是否自动列宽
     * @param fileOnExists  当文件存在是的处理方式
     * @return 生成文件路径
     * @throws java.io.IOException
     */
    public static String generate(String filePath, String fileName, POIFileType fileType, List<POITitle> titles, List datas, POIDataLoader POIDataLoader, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        filePath = EmptyUtil.isEmpty(filePath) ? POIDownload.class.getResource("/").getPath() : filePath;
        fileName = EmptyUtil.isEmpty(fileName) ? Identities.uuid() : fileName; //若未指定文件名，使用uuid
        fileType = EmptyUtil.isEmpty(fileType) ? POIFileType.XLS : fileType; //若未指定文件类型，默认使用03兼容格式

        File folder = new File(filePath);
        if (!folder.exists()) {
            folder.mkdir();
        }

        String url = filePath + File.separator + fileName + "." + fileType.getSuf(); //文件全路径

        /*
            创建03工作簿
         */
        Workbook workbook;
        if (fileType.equals(POIFileType.XLS)) { //03
            workbook = new HSSFWorkbook();
        } else { //07
            workbook = new XSSFWorkbook();
        }

        CellStyle cellStyleDefault = new POICellThemeDefault().theme(workbook); //默认单元格样式

        boolean hasTitle = false; //是否拥有标题行
        if (EmptyUtil.isNotEmpty(titles)) {
            hasTitle = true;
        }

        //若包含数据集，生成标题行（根据是否拥有标题行）及excel数据
        //若无数据，只生成一个sheet并生成标题（根据是否拥有标题行）
        if (EmptyUtil.isNotEmpty(datas) && datas.size() > 0) {
            int beginRow = 0;
            int index = 0;
            while (beginRow < datas.size()) {

                Sheet sheet = workbook.createSheet("sheet" + index); //创建工作表

                //创建标题
                if (hasTitle) {
                    //创建标题行
                    Row row = sheet.createRow(0);
                    //创建标题单元格
                    for (int i = 0; i < titles.size(); i++) {
                        POITitle title = titles.get(i);

                        if (EmptyUtil.isEmpty(title)) continue;

                        Cell cell = row.createCell(i);
                        if (EmptyUtil.isNotEmpty(title.getCellStyle())) {
                            cell.setCellStyle(title.getCellStyle().theme(workbook));
                        } else {
                            cell.setCellStyle(cellStyleDefault);
                        }
                        cell.setCellValue(title.getName());
                    }
                }

                int endRow = (index + 1) * (fileType.getMaxRow() - (hasTitle ? 1 : 0));
                endRow = endRow <= datas.size() ? endRow : datas.size();
                POIDataLoader.load(sheet, titles, datas, beginRow, endRow); //生成数据

                if (autoWidth) {
                    if (!hasTitle) {
                        titles = new ArrayList<POITitle>();
                        Map<String, Object> firstRow = (Map<String, Object>) datas.get(0);
                        for (String key : firstRow.keySet()) {
                            titles.add(new POITitle(key, key));
                        }
                    }
                    POIStyleUtil.autoSizeColumn(sheet, titles.size()); //自动宽度
                }

                index++;
                beginRow += fileType.getMaxRow() - 1;
            }
        } else {
            Sheet sheet = workbook.createSheet("sheet0"); //创建工作表

            //创建标题
            if (hasTitle) {
                //创建标题行
                Row row = sheet.createRow(0);
                //创建标题单元格
                for (int i = 0; i < titles.size(); i++) {
                    POITitle title = titles.get(i);

                    if (EmptyUtil.isEmpty(title)) continue;

                    Cell cell = row.createCell(i);
                    if (EmptyUtil.isNotEmpty(title.getCellStyle())) {
                        cell.setCellStyle(title.getCellStyle().theme(workbook));
                    } else {
                        cell.setCellStyle(cellStyleDefault);
                    }
                    cell.setCellValue(title.getName());
                }

                if (autoWidth) {
                    POIStyleUtil.autoSizeColumn(sheet, titles.size()); //自动宽度
                }
            }
        }

        /*
            写入文件
         */
        File excelFile = new File(url);
        if (excelFile.exists()) {
            switch (fileOnExists) {
                case RENAME_ON_EXISTS:
                    String urlRep = filePath + File.separator + fileName + "_" + Identities.uuid() + "." + fileType.getSuf(); //重复时重命名文件全路径
                    excelFile.renameTo(new File(urlRep)); //重命名
                    break;
                case DELETE_ON_EXISTS:
                    excelFile.delete(); //删除
                    break;
                case RETURNOLD_ON_EXISTS:
                    return excelFile.getPath();
            }
        }
        FileOutputStream os = new FileOutputStream(excelFile);
        workbook.write(os);
        os.close();

        return url;
    }

    public static String generate(String filePath, String fileName, POIFileType fileType, List<POITitle> titles, POIFileSaveType fileOnExists) throws IOException {
        return generate(filePath, fileName, fileType, titles, null, null, true, fileOnExists);
    }

    public static String generate(String filePath, POIFileType fileType, List<POITitle> titles, POIFileSaveType fileOnExists) throws IOException {
        return generate(filePath, null, fileType, titles, fileOnExists);
    }

    public static String generateFromJson(String filePath, String fileName, POIFileType fileType, List<POITitle> titles, List<JSONObject> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generate(filePath, fileName, fileType, titles, datas, new POIDataLoaderJson(), autoWidth, fileOnExists);
    }

    public static String generateFromJson(String filePath, String fileName, POIFileType fileType, List<JSONObject> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generateFromJson(filePath, fileName, fileType, null, datas, autoWidth, fileOnExists);
    }

    public static String generateFromJson(String filePath, POIFileType fileType, List<POITitle> titles, List<JSONObject> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generateFromJson(filePath, null, fileType, titles, datas, autoWidth, fileOnExists);
    }

    public static String generateFromJson(String filePath, POIFileType fileType, List<JSONObject> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generateFromJson(filePath, null, fileType, null, datas, autoWidth, fileOnExists);
    }

    public static String generateFromMap(String filePath, String fileName, POIFileType fileType, List<POITitle> titles, List<Map<String, Object>> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generate(filePath, fileName, fileType, titles, datas, new POIDataLoaderMap(), autoWidth, fileOnExists);
    }

    public static String generateFromMap(String filePath, String fileName, POIFileType fileType, List<Map<String, Object>> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generateFromMap(filePath, fileName, fileType, null, datas, autoWidth, fileOnExists);
    }

    public static String generateFromMap(String filePath, POIFileType fileType, List<POITitle> titles, List<Map<String, Object>> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generateFromMap(filePath, null, fileType, titles, datas, autoWidth, fileOnExists);
    }

    public static String generateFromMap(String filePath, POIFileType fileType, List<Map<String, Object>> datas, boolean autoWidth, POIFileSaveType fileOnExists) throws IOException {
        return generateFromMap(filePath, null, fileType, null, datas, autoWidth, fileOnExists);
    }

    /*
        rename
     */
    public static String generate(String filePath, String fileName, POIFileType fileType, List<POITitle> titles) throws IOException {
        return generate(filePath, fileName, fileType, titles, null, null, true, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generate(String filePath, POIFileType fileType, List<POITitle> titles) throws IOException {
        return generate(filePath, null, fileType, titles, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromJson(String filePath, String fileName, POIFileType fileType, List<POITitle> titles, List<JSONObject> datas, boolean autoWidth) throws IOException {
        return generate(filePath, fileName, fileType, titles, datas, new POIDataLoaderJson(), autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromJson(String filePath, String fileName, POIFileType fileType, List<JSONObject> datas, boolean autoWidth) throws IOException {
        return generateFromJson(filePath, fileName, fileType, null, datas, autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromJson(String filePath, POIFileType fileType, List<POITitle> titles, List<JSONObject> datas, boolean autoWidth) throws IOException {
        return generateFromJson(filePath, null, fileType, titles, datas, autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromJson(String filePath, POIFileType fileType, List<JSONObject> datas, boolean autoWidth) throws IOException {
        return generateFromJson(filePath, null, fileType, null, datas, autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromMap(String filePath, String fileName, POIFileType fileType, List<POITitle> titles, List<Map<String, Object>> datas, boolean autoWidth) throws IOException {
        return generate(filePath, fileName, fileType, titles, datas, new POIDataLoaderMap(), autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromMap(String filePath, String fileName, POIFileType fileType, List<Map<String, Object>> datas, boolean autoWidth) throws IOException {
        return generateFromMap(filePath, fileName, fileType, null, datas, autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromMap(String filePath, POIFileType fileType, List<POITitle> titles, List<Map<String, Object>> datas, boolean autoWidth) throws IOException {
        return generateFromMap(filePath, null, fileType, titles, datas, autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }

    public static String generateFromMap(String filePath, POIFileType fileType, List<Map<String, Object>> datas, boolean autoWidth) throws IOException {
        return generateFromMap(filePath, null, fileType, null, datas, autoWidth, POIFileSaveType.RENAME_ON_EXISTS);
    }
}